package com.gopay.bis.nucc.expay.operation;


import com.gopay.bis.common.util.BankLogUtils;
import com.gopay.common.constants.proccode.ProcCodeConstants;
import com.gopay.common.domain.bank.ExPayBaseMessage;
import com.gopay.common.domain.bank.nucc.expay.NuccExpayBaseMessage;
import com.gopay.common.domain.bank.nucc.expay.NuccExpayHeaderMessage;
import com.gopay.common.domain.bank.nucc.expay.cert.NuccExpayCertBodySgninf;
import com.gopay.common.domain.bank.nucc.expay.cert.req.NuccExpayCertBodyReq;
import com.gopay.common.domain.bank.nucc.expay.common.NuccExpayCommonRes;
import com.gopay.common.exception.GopayException;
import com.thoughtworks.xstream.XStream;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.StringUtils;
import org.springframework.beans.factory.annotation.Value;


/** 
 * 网联快捷工具类
 * @ClassName: NuccExPayCertHelper 
 * @author w_jiqing 
 * @date 2017年7月14日 下午5:31:41  
 */ 
public class NuccExPayCertHelper {
    
    private final static String XML_HEADER = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>";

    /**
     * 国付宝私钥存放地址
     */
    @Value("${gopay.private.key.path}")
    private String privateKeyPath;

    /**
     * 网联公钥存放地址
     */
    @Value("${nucc.public.key.path}")
    private String publicKeyPath;
    
    
    
    /** 
     * 使用私钥解密
     * @param data
     * @return
     * @throws GopayException 
     * @author zhoutong
     */
    public String decryptByPrivateKey(String data) throws GopayException{
        try{
            byte[] decryptByte = CertificateCoder.decryptByPrivateKey(Base64.decodeBase64(data),privateKeyPath);
            return StringUtils.newStringUtf8(decryptByte);
        }catch(Exception e){
            throw new GopayException(ProcCodeConstants.PROC_CODE_100E6076);
        }
        
    }
    
    /** 
     * 对用户要素信息进行加密
     * @param base
     * @throws GopayException 
     * @author w_jiqing 
     */
    public NuccExpayBaseMessage certEncrypt(ExPayBaseMessage base) throws GopayException{
        NuccExpayBaseMessage message =(NuccExpayBaseMessage) base;
        String key =AesEncryptUtils.getRandomString(32);
        NuccExpayHeaderMessage header= message.getMsgHeader();
        NuccExpayCertBodyReq body= (NuccExpayCertBodyReq) message.getMsgBody();
        NuccExpayCertBodySgninf sgnInf = body.getSgninf();        
        try {
            String sgnAcctId =Base64.encodeBase64String(AesEncryptUtils.Aes256Encode(sgnInf.getSgnAcctId(), key));
            sgnInf.setSgnAcctId(sgnAcctId);
            String sgnAcctNm =Base64.encodeBase64String(AesEncryptUtils.Aes256Encode(sgnInf.getSgnAcctNm(), key));
            sgnInf.setSgnAcctNm(sgnAcctNm);
            String idNo =Base64.encodeBase64String(AesEncryptUtils.Aes256Encode(sgnInf.getIdNo(), key));
            sgnInf.setIdNo(idNo);
            String mobNo =Base64.encodeBase64String(AesEncryptUtils.Aes256Encode(sgnInf.getMobNo(), key));
            sgnInf.setMobNo(mobNo);
            key = "01|"+key;
            String dgtlEnvlp = Base64.encodeBase64String(CertificateCoder.encryptByPublicKey(key,publicKeyPath));
            header.setDgtlEnvlp(dgtlEnvlp);
        } catch (Exception e) {
            BankLogUtils.printExPayExceptionLog(message, e);
            throw new GopayException(ProcCodeConstants.PROC_CODE_100E6076);
        }
        return message;
    }
    
    
    
    /** 
     * 签名 
     * @param base
     * @return
     * @throws GopayException 
     * @author w_jiqing 
     */
    public NuccExpayBaseMessage sign(ExPayBaseMessage base) throws GopayException{
        NuccExpayBaseMessage message = (NuccExpayBaseMessage) base;
        try {            
            XStream xstream = new XStream();
            StringBuffer returnStr = new StringBuffer();
            xstream.autodetectAnnotations(true);
            xstream.aliasSystemAttribute(null, "class");
            String xmlStr = xstream.toXML(message);
            returnStr.append(XML_HEADER);
            returnStr.append("\r\n");
            returnStr.append(xmlStr);
            String plainMsg = returnStr.toString();
            message.setPlainMessage(plainMsg);
            BankLogUtils.printExPaySignSendLog(message);
            byte[] base64SingDataBytes = CertificateCoder.sign(xmlStr,  privateKeyPath, "SHA256withRSA");
            String signMessage ="{S:"+Base64.encodeBase64String(base64SingDataBytes)+"}";
            message.setSignMessage(signMessage);
            BankLogUtils.printExPaySignReturnLog(message,"");
        }  catch (Exception e) {
            BankLogUtils.printExPayExceptionLog(message, e);
            throw new GopayException(ProcCodeConstants.PROC_CODE_100E6076);
        }
        return message;
        
    }
    
    /** 
     * 通用响应报文签名
     * @param base
     * @return
     * @throws GopayException 
     * @author w_jiqing 
     */
    public ExPayBaseMessage endSign(ExPayBaseMessage base) throws GopayException{
        NuccExpayCommonRes message = (NuccExpayCommonRes) base;
        try{
            XStream xstream = new XStream();
            StringBuffer returnStr = new StringBuffer();
            xstream.autodetectAnnotations(true);
            xstream.aliasSystemAttribute(null, "class");
            String xmlStr = xstream.toXML(message);
            returnStr.append(XML_HEADER);
            returnStr.append("\r\n");
            returnStr.append(xmlStr);
            String plainMsg = returnStr.toString();
            message.setPlainMessage(plainMsg);
            BankLogUtils.printExPaySignSendLog(message);
            byte[] base64SingDataBytes = CertificateCoder.sign(xmlStr,  privateKeyPath, "SHA256withRSA");
            String signMessage ="{S:"+Base64.encodeBase64String(base64SingDataBytes)+"}";
            message.setSignMessage(signMessage);
            BankLogUtils.printExPaySignReturnLog(message,"");
        }  catch (Exception e) {
            BankLogUtils.printExPayExceptionLog(message, e);
            throw new GopayException(ProcCodeConstants.PROC_CODE_100E6076);
        }
        return message;
        
        
    }
    
    /** 
     * 验证我司的私钥和网联发给我司的公钥是否匹配 
     * @param args 
     * @author w_jiqing 
     */
    public static void main(String[] args) {
        try {
            String sign = Base64.encodeBase64String(CertificateCoder.sign("11111","C:\\Users\\w_jiqing\\Desktop\\网联生产证书\\生产\\privateNuccProd.pem","SHA256withRSA"));
            boolean fals = CertificateCoder.verify("11111", sign, "C:\\Users\\w_jiqing\\Desktop\\网联生产证书\\生产\\GfbProd.cer");
            System.out.println(fals);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    /**
     * 验签 
     * @param res
     * @param resCla
     * @param resCla
     * @return
     * @throws GopayException 
     * @author w_jiqing 
     */
    public Object verify(String res,Class resCla) throws GopayException{
        boolean flag = false;
        String plainMsg ="";
        String signMsg ="";
        try{
            int indexPStart = res.indexOf("<root");
            int indexPEnd = res.indexOf("</root>");
            int indexSStart = res.indexOf("{S:");
            int indexSEnd = res.indexOf("}");
            if(indexPStart > -1 && indexPEnd > -1 && indexSStart > -1 && indexSEnd > -1){
                plainMsg = res.substring(indexPStart,indexPEnd+7);
                signMsg = res.substring(indexSStart+3,indexSEnd);
            }else{
                throw new GopayException(ProcCodeConstants.PROC_CODE_100E6079);
            }
            flag= CertificateCoder.verify(plainMsg, signMsg, publicKeyPath);
            if(flag){
                XStream xstream = new XStream();
                xstream.ignoreUnknownElements();
                xstream.autodetectAnnotations(true);
                xstream.processAnnotations(resCla);
                return xstream.fromXML(plainMsg);
            }else{
                throw new GopayException(ProcCodeConstants.PROC_CODE_100E6079);
            }            
        }catch(Exception ex){
            throw new GopayException(ProcCodeConstants.PROC_CODE_100E6079,ex.getMessage());
        }
    }
    
    /** 
     * 验签
     * @param message
     * @return
     * @throws GopayException 
     * @author w_jiqing 
     */
    public Object verify(ExPayBaseMessage message) throws GopayException{
        boolean flag = false;
        String plainMsg ="";
        String signMsg ="";
        try{
            plainMsg = message.getPlainMessage();
            signMsg = message.getSignMessage();
            flag= CertificateCoder.verify(plainMsg, signMsg, publicKeyPath);
        }catch(Exception ex){
            throw new GopayException(ProcCodeConstants.PROC_CODE_100E6079,ex.getMessage());
        }
        return flag;
    }

}
